"""风险指标计算模块."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Dict, Iterable, Optional

import numpy as np
import pandas as pd


@dataclass(frozen=True)
class VolatilityMetrics:
    rolling_volatility: Dict[int, float]
    annualized_volatility: Optional[float]


@dataclass(frozen=True)
class DrawdownMetrics:
    max_drawdown: float
    peak_date: pd.Timestamp
    trough_date: pd.Timestamp


@dataclass(frozen=True)
class LiquidityMetrics:
    average_volume: float
    median_volume: float
    turnover_ratio: Optional[float]


def calculate_rolling_volatility(
    returns: pd.Series, windows: Iterable[int] = (20, 60)
) -> VolatilityMetrics:
    """计算滚动波动率."""

    if returns.isna().all():
        raise ValueError("收益率序列全部缺失")

    volatility = {}
    for window in windows:
        rolling_std = returns.rolling(window, min_periods=window).std()
        volatility[window] = float(rolling_std.dropna().iloc[-1]) if not rolling_std.dropna().empty else float("nan")

    annualized = returns.std() * np.sqrt(252) if not returns.dropna().empty else None

    return VolatilityMetrics(rolling_volatility=volatility, annualized_volatility=annualized)


def calculate_max_drawdown(prices: pd.Series) -> DrawdownMetrics:
    """计算最大回撤."""

    if prices.isna().all():
        raise ValueError("价格序列全部缺失")

    cum_max = prices.cummax()
    drawdown = prices / cum_max - 1
    trough_idx = drawdown.idxmin()
    peak_idx = prices.loc[:trough_idx].idxmax()

    return DrawdownMetrics(
        max_drawdown=float(drawdown.loc[trough_idx]),
        peak_date=peak_idx,
        trough_date=trough_idx,
    )


def calculate_liquidity_metrics(
    volume: pd.Series, shares_outstanding: Optional[int] = None
) -> LiquidityMetrics:
    """计算流动性指标."""

    if volume.isna().all():
        raise ValueError("成交量序列全部缺失")

    avg_volume = float(volume.mean())
    median_volume = float(volume.median())
    turnover = (
        float(avg_volume / shares_outstanding)
        if shares_outstanding and shares_outstanding > 0
        else None
    )

    return LiquidityMetrics(
        average_volume=avg_volume,
        median_volume=median_volume,
        turnover_ratio=turnover,
    )


def calculate_var(returns: pd.Series, confidence: float = 0.95) -> float:
    """基于历史模拟的 VaR."""

    if returns.dropna().empty:
        raise ValueError("收益率序列为空，无法计算 VaR")

    alpha = 1 - confidence
    return float(np.quantile(returns.dropna(), alpha))

